rm(list = ls())
library("rstudioapi")
setwd(dirname(getActiveDocumentContext()$path))

Uncomment and run this block if you haven’t had these packages installed

# install.packages("ona", repos = c("https://cran.qe-libs.org", "https://cran.rstudio.org"))
# install.packages("tma", repos = c("https://cran.qe-libs.org", "https://cran.rstudio.org"))
# install.packages("magrittr")

0. setting up constant variables (change as appropriate)

mapid = "23230129"
# mapid = "24096504"
wd = paste0(getwd(), "/data/")

0. read A B C matrices and other relevant data

A_matrix = read_csv(paste0(wd, mapid, "_a_matrix.csv"))
B_matrix = read_csv(paste0(wd, mapid, "_b_matrix.csv"))
C_matrix = read.csv(paste0(wd, mapid, "_c_matrix.csv"))
sh_info = read.csv(paste0(wd, "LEM text - Stakeholders.csv"))
A = jsonlite::read_json(paste0(wd, mapid, "_init_map.json"))
reps = jsonlite::read_json(paste0(wd, mapid, "_reps.json"))
sub_result = readRDS(paste0(wd, mapid, "a_sub_result_new.rds")) #record satisfy level
sh_name = A_matrix %>%
  select(c(Name)) %>%
  unique() %>%
  pull()
sh_info = sh_info %>% 
  filter(Name %in% sh_name) %>% 
  arrange(match(Name, sh_name)) %>% 
  unite("SHinfo", Name:Direction, remove = TRUE) %>% 
  pull()
name_col = sh_name
ind_col = c()
dir_col = c()
group_col = c()
for (i in 1:length(A$indicators)) {
  for (j in 1:length(A$indicators[[i]]$stakeholders)) {
    ind_col <- append(ind_col, A$indicators[[i]]$stakeholders[[j]]$indKey)
    dir_col <- append(dir_col, A$indicators[[i]]$stakeholders[[j]]$direction)
    group_col <- append(group_col, A$indicators[[i]]$stakeholders[[j]]$stakeholderGroup)
  }
}
sh_df <- data.frame(name = name_col, indicator = ind_col, direction = dir_col, group = group_col)
sh_df
business <- sh_df %>% filter(group == "Local Business Consortium")
business <- business$name
environmental <- sh_df %>% filter(group == "Environmental Justice Center")
environmental <- environmental$name
community <- sh_df %>% filter(group == "Community Coalition")
community <- community$name
submission_name = C_matrix$user_name
submission_order = c()
sub_approval_count = c()
sub_order_num= c()


for (i in 1:length(sub_result)){
  submission_order = append(submission_order, sub_result[[i]]$userKey)
  sub_order_num = append(sub_order_num, sub_result[[i]]$submissionCount)
  sub_approval_count = append(sub_approval_count, sub_result[[i]]$approvalCount)
}
submission_df <- data.frame(userKey = submission_order, submissionCount = sub_order_num, approvalCount = sub_approval_count)
uniqueUsers <- unique(submission_df$userKey)
print(submission_df)
print(uniqueUsers)
 [1] "Benji"           "isahugh03"       "Kukuw27"         "hayleysalthouse" "cmangum"         "trentonjackson1" "sethapple123"   
 [8] "christianatw4"   "catw4"           "jkuethe03"       "matthewb08675"   "urusai"          "LED_57"          "Mercedes"       
[15] "abrooks11"       "ghinamoh07"      "Mark.Blakely"    "AidanC126"       "Richard"         "mckenzieakbari"  "kendalljackson" 
[22] "planetpat12"     "MichaelGaines"   "igudino"         "trentonjackson"  "Lexiiiii"        "carolinemott"    "nghiavo"        
[29] "SOS001F"         "Jimmy"           "LeoMunoz"        "WilliamJPayne"   "brookea1255"     "tigisesay"       "ChloeLineberry" 
[36] "albertaeinstein" "melissak1"       "benswit123"      "cwhitmore"       "jforbes"         "amandaPdavis"    "lilyking1103"   
[43] "landenramsey"    "Mshah1"          "emmamcnamara"    "katierakes27"    "twhitf496"       "amrit204"        "landyn.roberts" 
[50] "CalebHeacox"     "Rubyd1"         

Filter only users with more than 2 submissions

uniqueUsers_filtered <- submission_df %>%
  group_by(userKey) %>% 
  summarise(Count = n()) %>%
  filter(Count > 2)

uniqueUsers_filtered <- uniqueUsers_filtered$userKey
numPlots <- 7 # adjust as appropriate
batchSize <- ceiling(length(uniqueUsers_filtered) / numPlots)

for (i in 1:numPlots) {
  batch <- submission_df %>% filter(userKey %in% uniqueUsers_filtered[(((i-1) * batchSize) + 1):(min(length(uniqueUsers_filtered), i * batchSize))])
  
  # Create a line plot using ggplot2
  p <- ggplot(batch, aes(x = submissionCount, y = approvalCount, color = userKey, linetype = userKey)) +
    geom_line(size=1) +
    scale_x_continuous(breaks = 1:nrow(submission_df), labels = 1:nrow(submission_df), minor_breaks = NULL) +
    scale_y_continuous(breaks = seq(0, max(submission_df$approvalCount), by = 1), minor_breaks = NULL) +
    theme_minimal()
  print(p)
}

Prepare dataframe for stacked barplot

submission_detailed_df <- data.frame(userKey = character(), submissionCount = integer(), business = integer(),
                                     businessMax = integer(), environmental = integer(), environmentalMax = integer(),
                                     community = integer(), communityMax = integer())
for (i in 1:length(sub_result)) {
  if (sub_result[[i]]$userKey %in% uniqueUsers_filtered) {
    b_max = sum(business %in% sub_result[[i]]$stakeholders)
    e_max = sum(environmental %in% sub_result[[i]]$stakeholders)
    c_max = sum(community %in% sub_result[[i]]$stakeholders)
    b_select = sub_result[[i]]$stakeholders[sub_result[[i]]$stakeholders %in% business]
    e_select = sub_result[[i]]$stakeholders[sub_result[[i]]$stakeholders %in% environmental]
    c_select = sub_result[[i]]$stakeholders[sub_result[[i]]$stakeholders %in% community]
    b_count = 0
    e_count = 0
    c_count = 0
    for (b in b_select) {
      b_count = b_count + sub_result[[i]]$stakeholderApproval[[b]]
    }
    for (e in e_select) {
      e_count = e_count + sub_result[[i]]$stakeholderApproval[[e]]
    }
    for (c in c_select) {
      c_count = c_count + sub_result[[i]]$stakeholderApproval[[c]]
    }
    submission_detailed_df <- rbind(submission_detailed_df, data.frame(userKey = sub_result[[i]]$userKey,
                                    submissionCount = sub_result[[i]]$submissionCount, business = b_count,
                                    businessMax = b_max, environmental = e_count, environmentalMax = e_max,
                                    community = c_count, communityMax = c_max))
  }
}
bar_width = 0.5
dodge_width <- 0  # Adjust this as needed
expand_mults <- c(0, 0.5)
submissionCount_levels <- as.character(unique(submission_detailed_df$submissionCount))
for (user in uniqueUsers_filtered) {
  b_plot <- ggplot(submission_detailed_df %>% filter(userKey == user), aes(x = factor(submissionCount))) +
    geom_bar(aes(y = businessMax), stat = "identity", fill = "gainsboro", position = position_dodge(width = dodge_width), width = bar_width) +
    geom_bar(aes(y = business), stat = "identity", fill = "cornflowerblue", position = position_dodge(width = dodge_width), width = bar_width) +
    labs(title = "Business",
         x = "submissionCount",
         y = "count",
         fill = "Variable") +
    theme_minimal()
  # +
  #   scale_x_discrete(expand = expand_scale(mult = expand_mults, add = c(0, 0)))
  # Assuming the range of your y-axis is known or can be calculated:
  y_max <- max(submission_detailed_df$businessMax, na.rm = TRUE)
  # Create a sequence from 1 to the maximum value of y, by 1 unit interval
  hlines <- seq(1, y_max, by = 1)
  # Add horizontal lines to the plot
  b_plot <- b_plot + geom_hline(yintercept = hlines, color = "white", linetype = "solid")
  
  e_plot <- ggplot(submission_detailed_df %>% filter(userKey == user), aes(x = factor(submissionCount))) +
    geom_bar(aes(y = environmentalMax), stat = "identity", fill = "gainsboro", position = position_dodge(width = dodge_width), width = bar_width) +
    geom_bar(aes(y = environmental), stat = "identity", fill = "forestgreen", position = position_dodge(width = dodge_width), width = bar_width) +
    labs(title = "Environmental",
         x = "submissionCount",
         y = "count",
         fill = "Variable") +
    theme_minimal()
  y_max <- max(submission_detailed_df$environmentalMax, na.rm = TRUE)
  hlines <- seq(1, y_max, by = 1)
  e_plot <- e_plot + geom_hline(yintercept = hlines, color = "white", linetype = "solid")
  
  c_plot <- ggplot(submission_detailed_df %>% filter(userKey == user), aes(x = factor(submissionCount))) +
    geom_bar(aes(y = communityMax), stat = "identity", fill = "gainsboro", position = position_dodge(width = dodge_width), width = bar_width) +
    geom_bar(aes(y = community), stat = "identity", fill = "darkorange", position = position_dodge(width = dodge_width), width = bar_width) +
    labs(title = "Community",
         x = "submissionCount",
         y = "count",
         fill = "Variable") +
    theme_minimal()
  y_max <- max(submission_detailed_df$communityMax, na.rm = TRUE)
  hlines <- seq(1, y_max, by = 1)
  c_plot <- c_plot + geom_hline(yintercept = hlines, color = "white", linetype = "solid")
  
  print((b_plot / e_plot / c_plot) +
    plot_annotation(title = user))
}

ONA Section

1. combine conservation and limited use and set self-connection to zero

which means luc_1_X + luc_4_X, luc_X_1 + luc_X_4

A_matrix_2 <- A_matrix
B_matrix_2 <- B_matrix
C_matrix_2 <- C_matrix
for (i in 1:11) {
  A_luc1x = which(names(A_matrix_2)==paste0("luc_", 1, "_", i-1))
  A_luc4x = which(names(A_matrix_2)==paste0("luc_", 4, "_", i-1))
  B_luc1x = which(names(B_matrix_2)==paste0("luc_", 1, "_", i-1))
  B_luc4x = which(names(B_matrix_2)==paste0("luc_", 4, "_", i-1))
  C_luc1x = which(names(C_matrix_2)==paste0("luc_", 1, "_", i-1))
  C_luc4x = which(names(C_matrix_2)==paste0("luc_", 4, "_", i-1))
  A_matrix_2[[A_luc1x]] <- A_matrix_2[[A_luc1x]] + A_matrix_2[[A_luc4x]]
  B_matrix_2[[B_luc1x]] <- B_matrix_2[[B_luc1x]] + B_matrix_2[[B_luc4x]]
  C_matrix_2[[C_luc1x]] <- C_matrix_2[[C_luc1x]] + C_matrix_2[[C_luc4x]]
}
for (i in 1:11) {
  A_lucx1 = which(names(A_matrix_2)==paste0("luc_", i-1, "_", 1))
  A_lucx4 = which(names(A_matrix_2)==paste0("luc_", i-1, "_", 4))
  B_lucx1 = which(names(B_matrix_2)==paste0("luc_", i-1, "_", 1))
  B_lucx4 = which(names(B_matrix_2)==paste0("luc_", i-1, "_", 4))
  C_lucx1 = which(names(C_matrix_2)==paste0("luc_", i-1, "_", 1))
  C_lucx4 = which(names(C_matrix_2)==paste0("luc_", i-1, "_", 4))
  A_matrix_2[[A_lucx1]] <- A_matrix_2[[A_lucx1]] + A_matrix_2[[A_lucx4]]
  B_matrix_2[[B_lucx1]] <- B_matrix_2[[B_lucx1]] + B_matrix_2[[B_lucx4]]
  C_matrix_2[[C_lucx1]] <- C_matrix_2[[C_lucx1]] + C_matrix_2[[C_lucx4]]
}
for (i in 1:11) {
  A_lucxx = which(names(A_matrix_2)==paste0("luc_", i-1, "_", i-1))
  B_lucxx = which(names(B_matrix_2)==paste0("luc_", i-1, "_", i-1))
  C_lucxx = which(names(C_matrix_2)==paste0("luc_", i-1, "_", i-1))
  A_matrix_2[[A_lucxx]] = 0
  B_matrix_2[[B_lucxx]] = 0
  C_matrix_2[[C_lucxx]] = 0
}

A_matrix_2 <- A_matrix_2 %>% select(-c(luc_4_0, luc_4_1, luc_4_2, luc_4_3, luc_4_4, 
                               luc_4_5, luc_4_6, luc_4_7, luc_4_8, luc_4_9, luc_4_10,
                               luc_0_4, luc_1_4, luc_2_4, luc_3_4, luc_4_4,
                               luc_5_4, luc_6_4, luc_7_4, luc_8_4, luc_9_4, luc_10_4))
B_matrix_2 <- B_matrix_2 %>% select(-c(luc_4_0, luc_4_1, luc_4_2, luc_4_3, luc_4_4, 
                               luc_4_5, luc_4_6, luc_4_7, luc_4_8, luc_4_9, luc_4_10,
                               luc_0_4, luc_1_4, luc_2_4, luc_3_4, luc_4_4,
                               luc_5_4, luc_6_4, luc_7_4, luc_8_4, luc_9_4, luc_10_4))
C_matrix_2 <- C_matrix_2 %>% select(-c(luc_4_0, luc_4_1, luc_4_2, luc_4_3, luc_4_4, 
                               luc_4_5, luc_4_6, luc_4_7, luc_4_8, luc_4_9, luc_4_10,
                               luc_0_4, luc_1_4, luc_2_4, luc_3_4, luc_4_4,
                               luc_5_4, luc_6_4, luc_7_4, luc_8_4, luc_9_4, luc_10_4))

2. make ABC col names consistent for the ease of later work

colnames(A_matrix_2)[2] = "SH"
A_matrix_2 <- A_matrix_2 %>%
  select(-c(...1)) %>% 
  add_column(user_name = "NA", .before = "luc_0_0") %>%
  add_column(submission = "NA",.before = "luc_0_0") %>%
  add_column(index = 1:nrow(A_matrix), .before = "SH")
colnames(B_matrix_2)[2] = "SH"
B_matrix_2 <- B_matrix_2 %>%
  select(-c(...1)) %>% 
  add_column(user_name = "NA", .before = "luc_0_0") %>%
  add_column(submission = "NA",.before = "luc_0_0") %>%
  add_column(index = 1:nrow(B_matrix), .before = "SH")
C_matrix_2 <- C_matrix_2 %>%
  add_column(index = 1:nrow(C_matrix_2), .before = "user_name") %>%
  add_column(Name = "NA", .before = "user_name") %>%
  add_column(Satisfy = "NA",.before = "user_name") %>%
  add_column(N = "NA", .before = "user_name")

3.run ONA

call generate.ona.object function

generate.ona.object <- function(data, unit.col, meta.col, codes){
  output <- list()
  f.units <- unit.col
  ENA_UNIT <- rENA::merge_columns_c(f.units, cols = colnames(f.units));
  # ENA_UNIT <-  f.units
  f.raw <- data
  f.codes <- codes
  dena_data = directedENA:::ena.set.directed(f.raw, f.units, NA, f.codes)
  output.meta.data <- meta.col
  dena_data$meta.data <- data.table::as.data.table(cbind(ENA_UNIT, output.meta.data))
  for( i in colnames(dena_data$meta.data) ) {
    set(dena_data$meta.data, j = i, value = rENA::as.ena.metadata(dena_data$meta.data[[i]]))
  }
  code_length <- length(dena_data$rotation$codes);
  dena_data$rotation$adjacency.key <- data.table::data.table(matrix(c(
    rep(1:code_length, code_length),
    rep(1:code_length, each = code_length)),
    byrow = TRUE, nrow = 2
  ))
  directed.adjacency.vectors <- as.ena.matrix(data.table::as.data.table(data[, grep("V", colnames(data))]), "ena.connections")
  # aren't these two the same thing 
  dena_data$connection.counts <- data.table::as.data.table(cbind(dena_data$meta.data, directed.adjacency.vectors))
  dena_data$connection.counts = rENA::as.ena.matrix(x = dena_data$connection.counts, "ena.connections")
  for (i in which(!rENA::find_meta_cols(dena_data$connection.counts)))
    set(dena_data$connection.counts, j = i, value = as.ena.co.occurrence(as.double(dena_data$connection.counts[[i]])))
  dena_data$model$row.connection.counts = data.table::as.data.table(cbind(dena_data$meta.data, directed.adjacency.vectors))
  dena_data$model$row.connection.counts <- rENA::as.ena.matrix(dena_data$model$row.connection.counts, "row.connections")
  output = dena_data;
  return(output)
}
# 1. prepare df

# df <- A_matrix
# df <- B_matrix
df <- C_matrix_2

names(df)[7:106] <- paste0("V",seq(1:100))
df$mapid = mapid

# 2. accum
accumC <- generate.ona.object(
  df,
  unit.col = df[,1:7],
  meta.col = df[,1:7],
  codes = as.vector(
    c("Commercial",
    "Conservation_lu",
    # "Conservation",
    "Cropland",
    "Industrial",
    # "Limited Use",
    "Pasture",
    "Recreation",
    "Residential HD",
    "Residential LD",
    "Timber",
    "Wetlands")))

# 3. model
setC <- model(accumC)

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution
# 4. GoF
correlations(setC)
NA
# 1. prepare df

df1 <- A_matrix_2
# df <- B_matrix
# df <- C_matrix

names(df1)[7:106] <- paste0("V",seq(1:100))
df1$mapid = mapid

# 2. accum
accumA <- generate.ona.object(
  df1,
  unit.col = df1[,1:7],
  meta.col = df1[,1:7],
  codes = as.vector(
    c("Commercial",
    "Conservation_lu",
    # "Conservation",
    "Cropland",
    "Industrial",
    # "Limited Use",
    "Pasture",
    "Recreation",
    "Residential HD",
    "Residential LD",
    "Timber",
    "Wetlands")))

# 3. model
setA <- model(accumA)

# 4. GoF
correlations(setA)

4. project C points into A space

To do so, I need to make a set using C’s accumulation and A’s rotation matrix

set=model(accumC, rotation.set = setA$rotation)

5. ona plotting

5.1 setting global visual parameters here so that all ONA plots we generate are on the same scale

node_size_multiplier = 0.2
node_position_multiplier = 1.0
edge_size_multiplier = 0.2
point_position_multiplier = 1.0
edge_arrow_saturation_multiplier = 1.0
ona:::plot.ena.ordered.set(setC) %>% 
  units( 
    points = setC$points,
    points_color = "black",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE)

5.2 quick check points ARE being rotated

ona:::plot.ena.ordered.set(setA, title = "space used for projection and its points") %>%
  units(
    points = setA$points,
    points_color = "gray",
    show_mean = TRUE, show_points = TRUE, with_ci = FALSE) %>%
 nodes(
    node_size_multiplier = 0.001) 

ona:::plot.ena.ordered.set(setC, title = "points need to be projected in its original space") %>%
  units( 
    points = setC$points,
    points_color = "black",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE)%>%
 nodes(
    node_size_multiplier = 0.001) 

ona:::plot.ena.ordered.set(set, title = "projected points in its new space") %>%
  units(
    points = set$points,
    points_color = "black",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE) %>%
  units(
    points = setA$points,
    points_color = "gray",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE) %>%
 nodes(
    node_size_multiplier = 0.001) 

Cluster Check:

ona:::plot.ena.ordered.set(setA, title = "space used for projection and its points") %>%
  units(
    points = setA$points,
    points_color = "gray",
    show_mean = TRUE, show_points = TRUE, with_ci = FALSE) %>%
 nodes(
    node_size_multiplier = 0.001) 
A = setA$points[ENA_DIRECTION== 'response']

Plot both bar plots and ona plots by specifying user

uniqueUsers_filtered
 [1] "AidanC126"       "ChloeLineberry"  "Jimmy"           "Kukuw27"         "LED_57"          "LeoMunoz"        "Lexiiiii"       
 [8] "Mark.Blakely"    "MichaelGaines"   "Mshah1"          "Richard"         "SOS001F"         "abrooks11"       "albertaeinstein"
[15] "amrit204"        "benswit123"      "brookea1255"     "carolinemott"    "catw4"           "christianatw4"   "cmangum"        
[22] "cwhitmore"       "emmamcnamara"    "ghinamoh07"      "hayleysalthouse" "igudino"         "isahugh03"       "jforbes"        
[29] "jkuethe03"       "katierakes27"    "kendalljackson"  "landenramsey"    "landyn.roberts"  "lilyking1103"    "matthewb08675"  
[36] "mckenzieakbari"  "melissak1"       "nghiavo"         "planetpat12"     "sethapple123"    "tigisesay"       "trentonjackson" 
[43] "trentonjackson1" "twhitf496"       "urusai"         
userkey = "AidanC126"

subs <- as.list(unique(set$points$ENA_UNIT))
subs <- subs[grepl(userkey, subs)] 
ona_plots <- list()

for (i in subs) {
  p <- ona:::plot.ena.ordered.set(set, title = paste0(i)) %>%
  edges(
      weights = set$line.weights[ENA_UNIT == i],
      edge_size_multiplier = edge_size_multiplier,
      edge_arrow_saturation_multiplier = edge_arrow_saturation_multiplier,
      node_position_multiplier = node_position_multiplier,
      edge_color = c("red")) %>%
  nodes(
    node_size_multiplier = node_size_multiplier,
    node_position_multiplier = node_position_multiplier,
    self_connection_color = "red")  %>%
  units(
      points=set$points[ENA_UNIT == i],
      points_color = "black",
      point_position_multiplier = point_position_multiplier,
      show_mean = FALSE, show_points = TRUE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[1] & Satisfy == "Yes"],
      points_color = "green",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[2] & Satisfy == "Yes"],
      points_color = "blue",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[3] & Satisfy == "Yes"],
      points_color = "brown",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[4] & Satisfy == "Yes"],
      points_color = "purple",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[5] & Satisfy == "Yes"],
      points_color = "yellow",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[6] & Satisfy == "Yes"],
      points_color = "deeppink",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[7] & Satisfy == "Yes"],
      points_color = "Tan",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[8] & Satisfy == "Yes"],
      points_color = "Cyan",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[9] & Satisfy == "Yes"],
      points_color = "orange",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE)%>% 
      plotly::layout(showlegend = TRUE, legend = list(x = 100, y = 0.9)) %>% 
      style(name = "point", traces = c(2)) %>% 
    style(name = sh_info[1], traces = c(3)) %>% 
    style(name = sh_info[2], traces = c(4)) %>% 
    style(name = sh_info[3], traces = c(5)) %>% 
    style(name = sh_info[4], traces = c(6)) %>% 
    style(name = sh_info[5], traces = c(7)) %>% 
    style(name = sh_info[6], traces = c(8)) %>% 
    style(name = sh_info[7], traces = c(9)) %>% 
    style(name = sh_info[8], traces = c(10)) %>% 
    style(name = sh_info[9], traces = c(11))
  ona_plots[[i]] <- p
}
bar_width = 0.5
dodge_width <- 0  # Adjust this as needed
expand_mults <- c(0, 0.5)
submissionCount_levels <- as.character(unique(submission_detailed_df$submissionCount))

b_plot <- ggplot(submission_detailed_df %>% filter(userKey == userkey), aes(x = factor(submissionCount))) +
  geom_bar(aes(y = businessMax), stat = "identity", fill = "gainsboro", position = position_dodge(width = dodge_width), width = bar_width) +
  geom_bar(aes(y = business), stat = "identity", fill = "cornflowerblue", position = position_dodge(width = dodge_width), width = bar_width) +
  labs(title = "Business",
       x = "submissionCount",
       y = "count",
       fill = "Variable") +
  theme_minimal()
# +
#   scale_x_discrete(expand = expand_scale(mult = expand_mults, add = c(0, 0)))
# Assuming the range of your y-axis is known or can be calculated:
y_max <- max(submission_detailed_df$businessMax, na.rm = TRUE)
# Create a sequence from 1 to the maximum value of y, by 1 unit interval
hlines <- seq(1, y_max, by = 1)
# Add horizontal lines to the plot
b_plot <- b_plot + geom_hline(yintercept = hlines, color = "white", linetype = "solid")

e_plot <- ggplot(submission_detailed_df %>% filter(userKey == userkey), aes(x = factor(submissionCount))) +
  geom_bar(aes(y = environmentalMax), stat = "identity", fill = "gainsboro", position = position_dodge(width = dodge_width), width = bar_width) +
  geom_bar(aes(y = environmental), stat = "identity", fill = "forestgreen", position = position_dodge(width = dodge_width), width = bar_width) +
  labs(title = "Environmental",
       x = "submissionCount",
       y = "count",
       fill = "Variable") +
  theme_minimal()
y_max <- max(submission_detailed_df$environmentalMax, na.rm = TRUE)
hlines <- seq(1, y_max, by = 1)
e_plot <- e_plot + geom_hline(yintercept = hlines, color = "white", linetype = "solid")

c_plot <- ggplot(submission_detailed_df %>% filter(userKey == userkey), aes(x = factor(submissionCount))) +
  geom_bar(aes(y = communityMax), stat = "identity", fill = "gainsboro", position = position_dodge(width = dodge_width), width = bar_width) +
  geom_bar(aes(y = community), stat = "identity", fill = "darkorange", position = position_dodge(width = dodge_width), width = bar_width) +
  labs(title = "Community",
       x = "submissionCount",
       y = "count",
       fill = "Variable") +
  theme_minimal()
y_max <- max(submission_detailed_df$communityMax, na.rm = TRUE)
hlines <- seq(1, y_max, by = 1)
c_plot <- c_plot + geom_hline(yintercept = hlines, color = "white", linetype = "solid")

print((b_plot / e_plot / c_plot) +
  plot_annotation(title = userkey))


for (p in ona_plots) {
  print(p)
}
LS0tCnRpdGxlOiAiU3RvcnkgYW5hbHlzaXMgb2YgcGxheWVycyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9IAprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpIApgYGAKCmBgYHtyfQpybShsaXN0ID0gbHMoKSkKbGlicmFyeSgicnN0dWRpb2FwaSIpCnNldHdkKGRpcm5hbWUoZ2V0QWN0aXZlRG9jdW1lbnRDb250ZXh0KCkkcGF0aCkpCmBgYAoKVW5jb21tZW50IGFuZCBydW4gdGhpcyBibG9jayBpZiB5b3UgaGF2ZW4ndCBoYWQgdGhlc2UgcGFja2FnZXMgaW5zdGFsbGVkCmBgYHtyfQojIGluc3RhbGwucGFja2FnZXMoIm9uYSIsIHJlcG9zID0gYygiaHR0cHM6Ly9jcmFuLnFlLWxpYnMub3JnIiwgImh0dHBzOi8vY3Jhbi5yc3R1ZGlvLm9yZyIpKQojIGluc3RhbGwucGFja2FnZXMoInRtYSIsIHJlcG9zID0gYygiaHR0cHM6Ly9jcmFuLnFlLWxpYnMub3JnIiwgImh0dHBzOi8vY3Jhbi5yc3R1ZGlvLm9yZyIpKQojIGluc3RhbGwucGFja2FnZXMoIm1hZ3JpdHRyIikKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KG9uYSkKbGlicmFyeSh0bWEpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkockVOQSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShnZ2ZvcnRpZnkpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShzdXBlcmhlYXQpCmxpYnJhcnkocmpzb24pCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShyYW5kb21jb2xvUikKbGlicmFyeShybGlzdCkKbGlicmFyeSh3ZWJzaG90KQpsaWJyYXJ5KHBhdGNod29yaykKYGBgCgojIDAuIHNldHRpbmcgdXAgY29uc3RhbnQgdmFyaWFibGVzIChjaGFuZ2UgYXMgYXBwcm9wcmlhdGUpCmBgYHtyfQptYXBpZCA9ICIyMzIzMDEyOSIKIyBtYXBpZCA9ICIyNDA5NjUwNCIKd2QgPSBwYXN0ZTAoZ2V0d2QoKSwgIi9kYXRhLyIpCmBgYAoKIyAwLiByZWFkIEEgQiBDIG1hdHJpY2VzIGFuZCBvdGhlciByZWxldmFudCBkYXRhCmBgYHtyfQpBX21hdHJpeCA9IHJlYWRfY3N2KHBhc3RlMCh3ZCwgbWFwaWQsICJfYV9tYXRyaXguY3N2IikpCkJfbWF0cml4ID0gcmVhZF9jc3YocGFzdGUwKHdkLCBtYXBpZCwgIl9iX21hdHJpeC5jc3YiKSkKQ19tYXRyaXggPSByZWFkLmNzdihwYXN0ZTAod2QsIG1hcGlkLCAiX2NfbWF0cml4LmNzdiIpKQpzaF9pbmZvID0gcmVhZC5jc3YocGFzdGUwKHdkLCAiTEVNIHRleHQgLSBTdGFrZWhvbGRlcnMuY3N2IikpCkEgPSBqc29ubGl0ZTo6cmVhZF9qc29uKHBhc3RlMCh3ZCwgbWFwaWQsICJfaW5pdF9tYXAuanNvbiIpKQpyZXBzID0ganNvbmxpdGU6OnJlYWRfanNvbihwYXN0ZTAod2QsIG1hcGlkLCAiX3JlcHMuanNvbiIpKQpzdWJfcmVzdWx0ID0gcmVhZFJEUyhwYXN0ZTAod2QsIG1hcGlkLCAiYV9zdWJfcmVzdWx0X25ldy5yZHMiKSkgI3JlY29yZCBzYXRpc2Z5IGxldmVsCmBgYAoKYGBge3J9CnNoX25hbWUgPSBBX21hdHJpeCAlPiUKICBzZWxlY3QoYyhOYW1lKSkgJT4lCiAgdW5pcXVlKCkgJT4lCiAgcHVsbCgpCmBgYAoKYGBge3J9CnNoX2luZm8gPSBzaF9pbmZvICU+JSAKICBmaWx0ZXIoTmFtZSAlaW4lIHNoX25hbWUpICU+JSAKICBhcnJhbmdlKG1hdGNoKE5hbWUsIHNoX25hbWUpKSAlPiUgCiAgdW5pdGUoIlNIaW5mbyIsIE5hbWU6RGlyZWN0aW9uLCByZW1vdmUgPSBUUlVFKSAlPiUgCiAgcHVsbCgpCmBgYAoKYGBge3J9Cm5hbWVfY29sID0gc2hfbmFtZQppbmRfY29sID0gYygpCmRpcl9jb2wgPSBjKCkKZ3JvdXBfY29sID0gYygpCmZvciAoaSBpbiAxOmxlbmd0aChBJGluZGljYXRvcnMpKSB7CiAgZm9yIChqIGluIDE6bGVuZ3RoKEEkaW5kaWNhdG9yc1tbaV1dJHN0YWtlaG9sZGVycykpIHsKICAgIGluZF9jb2wgPC0gYXBwZW5kKGluZF9jb2wsIEEkaW5kaWNhdG9yc1tbaV1dJHN0YWtlaG9sZGVyc1tbal1dJGluZEtleSkKICAgIGRpcl9jb2wgPC0gYXBwZW5kKGRpcl9jb2wsIEEkaW5kaWNhdG9yc1tbaV1dJHN0YWtlaG9sZGVyc1tbal1dJGRpcmVjdGlvbikKICAgIGdyb3VwX2NvbCA8LSBhcHBlbmQoZ3JvdXBfY29sLCBBJGluZGljYXRvcnNbW2ldXSRzdGFrZWhvbGRlcnNbW2pdXSRzdGFrZWhvbGRlckdyb3VwKQogIH0KfQpzaF9kZiA8LSBkYXRhLmZyYW1lKG5hbWUgPSBuYW1lX2NvbCwgaW5kaWNhdG9yID0gaW5kX2NvbCwgZGlyZWN0aW9uID0gZGlyX2NvbCwgZ3JvdXAgPSBncm91cF9jb2wpCnNoX2RmCmBgYAoKYGBge3J9CmJ1c2luZXNzIDwtIHNoX2RmICU+JSBmaWx0ZXIoZ3JvdXAgPT0gIkxvY2FsIEJ1c2luZXNzIENvbnNvcnRpdW0iKQpidXNpbmVzcyA8LSBidXNpbmVzcyRuYW1lCmVudmlyb25tZW50YWwgPC0gc2hfZGYgJT4lIGZpbHRlcihncm91cCA9PSAiRW52aXJvbm1lbnRhbCBKdXN0aWNlIENlbnRlciIpCmVudmlyb25tZW50YWwgPC0gZW52aXJvbm1lbnRhbCRuYW1lCmNvbW11bml0eSA8LSBzaF9kZiAlPiUgZmlsdGVyKGdyb3VwID09ICJDb21tdW5pdHkgQ29hbGl0aW9uIikKY29tbXVuaXR5IDwtIGNvbW11bml0eSRuYW1lCmBgYAoKYGBge3J9CnN1Ym1pc3Npb25fbmFtZSA9IENfbWF0cml4JHVzZXJfbmFtZQpzdWJtaXNzaW9uX29yZGVyID0gYygpCnN1Yl9hcHByb3ZhbF9jb3VudCA9IGMoKQpzdWJfb3JkZXJfbnVtPSBjKCkKCgpmb3IgKGkgaW4gMTpsZW5ndGgoc3ViX3Jlc3VsdCkpewogIHN1Ym1pc3Npb25fb3JkZXIgPSBhcHBlbmQoc3VibWlzc2lvbl9vcmRlciwgc3ViX3Jlc3VsdFtbaV1dJHVzZXJLZXkpCiAgc3ViX29yZGVyX251bSA9IGFwcGVuZChzdWJfb3JkZXJfbnVtLCBzdWJfcmVzdWx0W1tpXV0kc3VibWlzc2lvbkNvdW50KQogIHN1Yl9hcHByb3ZhbF9jb3VudCA9IGFwcGVuZChzdWJfYXBwcm92YWxfY291bnQsIHN1Yl9yZXN1bHRbW2ldXSRhcHByb3ZhbENvdW50KQp9CmBgYAoKYGBge3J9CnN1Ym1pc3Npb25fZGYgPC0gZGF0YS5mcmFtZSh1c2VyS2V5ID0gc3VibWlzc2lvbl9vcmRlciwgc3VibWlzc2lvbkNvdW50ID0gc3ViX29yZGVyX251bSwgYXBwcm92YWxDb3VudCA9IHN1Yl9hcHByb3ZhbF9jb3VudCkKdW5pcXVlVXNlcnMgPC0gdW5pcXVlKHN1Ym1pc3Npb25fZGYkdXNlcktleSkKcHJpbnQoc3VibWlzc2lvbl9kZikKcHJpbnQodW5pcXVlVXNlcnMpCmBgYAoKRmlsdGVyIG9ubHkgdXNlcnMgd2l0aCBtb3JlIHRoYW4gMiBzdWJtaXNzaW9ucwpgYGB7cn0KdW5pcXVlVXNlcnNfZmlsdGVyZWQgPC0gc3VibWlzc2lvbl9kZiAlPiUKICBncm91cF9ieSh1c2VyS2V5KSAlPiUgCiAgc3VtbWFyaXNlKENvdW50ID0gbigpKSAlPiUKICBmaWx0ZXIoQ291bnQgPiAyKQoKdW5pcXVlVXNlcnNfZmlsdGVyZWQgPC0gdW5pcXVlVXNlcnNfZmlsdGVyZWQkdXNlcktleQpgYGAKCmBgYHtyfQpudW1QbG90cyA8LSA3ICMgYWRqdXN0IGFzIGFwcHJvcHJpYXRlCmJhdGNoU2l6ZSA8LSBjZWlsaW5nKGxlbmd0aCh1bmlxdWVVc2Vyc19maWx0ZXJlZCkgLyBudW1QbG90cykKCmZvciAoaSBpbiAxOm51bVBsb3RzKSB7CiAgYmF0Y2ggPC0gc3VibWlzc2lvbl9kZiAlPiUgZmlsdGVyKHVzZXJLZXkgJWluJSB1bmlxdWVVc2Vyc19maWx0ZXJlZFsoKChpLTEpICogYmF0Y2hTaXplKSArIDEpOihtaW4obGVuZ3RoKHVuaXF1ZVVzZXJzX2ZpbHRlcmVkKSwgaSAqIGJhdGNoU2l6ZSkpXSkKICAKICAjIENyZWF0ZSBhIGxpbmUgcGxvdCB1c2luZyBnZ3Bsb3QyCiAgcCA8LSBnZ3Bsb3QoYmF0Y2gsIGFlcyh4ID0gc3VibWlzc2lvbkNvdW50LCB5ID0gYXBwcm92YWxDb3VudCwgY29sb3IgPSB1c2VyS2V5LCBsaW5ldHlwZSA9IHVzZXJLZXkpKSArCiAgICBnZW9tX2xpbmUoc2l6ZT0xKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMTpucm93KHN1Ym1pc3Npb25fZGYpLCBsYWJlbHMgPSAxOm5yb3coc3VibWlzc2lvbl9kZiksIG1pbm9yX2JyZWFrcyA9IE5VTEwpICsKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgbWF4KHN1Ym1pc3Npb25fZGYkYXBwcm92YWxDb3VudCksIGJ5ID0gMSksIG1pbm9yX2JyZWFrcyA9IE5VTEwpICsKICAgIHRoZW1lX21pbmltYWwoKQogIHByaW50KHApCn0KYGBgCgpQcmVwYXJlIGRhdGFmcmFtZSBmb3Igc3RhY2tlZCBiYXJwbG90CmBgYHtyfQpzdWJtaXNzaW9uX2RldGFpbGVkX2RmIDwtIGRhdGEuZnJhbWUodXNlcktleSA9IGNoYXJhY3RlcigpLCBzdWJtaXNzaW9uQ291bnQgPSBpbnRlZ2VyKCksIGJ1c2luZXNzID0gaW50ZWdlcigpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnVzaW5lc3NNYXggPSBpbnRlZ2VyKCksIGVudmlyb25tZW50YWwgPSBpbnRlZ2VyKCksIGVudmlyb25tZW50YWxNYXggPSBpbnRlZ2VyKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tdW5pdHkgPSBpbnRlZ2VyKCksIGNvbW11bml0eU1heCA9IGludGVnZXIoKSkKZm9yIChpIGluIDE6bGVuZ3RoKHN1Yl9yZXN1bHQpKSB7CiAgaWYgKHN1Yl9yZXN1bHRbW2ldXSR1c2VyS2V5ICVpbiUgdW5pcXVlVXNlcnNfZmlsdGVyZWQpIHsKICAgIGJfbWF4ID0gc3VtKGJ1c2luZXNzICVpbiUgc3ViX3Jlc3VsdFtbaV1dJHN0YWtlaG9sZGVycykKICAgIGVfbWF4ID0gc3VtKGVudmlyb25tZW50YWwgJWluJSBzdWJfcmVzdWx0W1tpXV0kc3Rha2Vob2xkZXJzKQogICAgY19tYXggPSBzdW0oY29tbXVuaXR5ICVpbiUgc3ViX3Jlc3VsdFtbaV1dJHN0YWtlaG9sZGVycykKICAgIGJfc2VsZWN0ID0gc3ViX3Jlc3VsdFtbaV1dJHN0YWtlaG9sZGVyc1tzdWJfcmVzdWx0W1tpXV0kc3Rha2Vob2xkZXJzICVpbiUgYnVzaW5lc3NdCiAgICBlX3NlbGVjdCA9IHN1Yl9yZXN1bHRbW2ldXSRzdGFrZWhvbGRlcnNbc3ViX3Jlc3VsdFtbaV1dJHN0YWtlaG9sZGVycyAlaW4lIGVudmlyb25tZW50YWxdCiAgICBjX3NlbGVjdCA9IHN1Yl9yZXN1bHRbW2ldXSRzdGFrZWhvbGRlcnNbc3ViX3Jlc3VsdFtbaV1dJHN0YWtlaG9sZGVycyAlaW4lIGNvbW11bml0eV0KICAgIGJfY291bnQgPSAwCiAgICBlX2NvdW50ID0gMAogICAgY19jb3VudCA9IDAKICAgIGZvciAoYiBpbiBiX3NlbGVjdCkgewogICAgICBiX2NvdW50ID0gYl9jb3VudCArIHN1Yl9yZXN1bHRbW2ldXSRzdGFrZWhvbGRlckFwcHJvdmFsW1tiXV0KICAgIH0KICAgIGZvciAoZSBpbiBlX3NlbGVjdCkgewogICAgICBlX2NvdW50ID0gZV9jb3VudCArIHN1Yl9yZXN1bHRbW2ldXSRzdGFrZWhvbGRlckFwcHJvdmFsW1tlXV0KICAgIH0KICAgIGZvciAoYyBpbiBjX3NlbGVjdCkgewogICAgICBjX2NvdW50ID0gY19jb3VudCArIHN1Yl9yZXN1bHRbW2ldXSRzdGFrZWhvbGRlckFwcHJvdmFsW1tjXV0KICAgIH0KICAgIHN1Ym1pc3Npb25fZGV0YWlsZWRfZGYgPC0gcmJpbmQoc3VibWlzc2lvbl9kZXRhaWxlZF9kZiwgZGF0YS5mcmFtZSh1c2VyS2V5ID0gc3ViX3Jlc3VsdFtbaV1dJHVzZXJLZXksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Ym1pc3Npb25Db3VudCA9IHN1Yl9yZXN1bHRbW2ldXSRzdWJtaXNzaW9uQ291bnQsIGJ1c2luZXNzID0gYl9jb3VudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnVzaW5lc3NNYXggPSBiX21heCwgZW52aXJvbm1lbnRhbCA9IGVfY291bnQsIGVudmlyb25tZW50YWxNYXggPSBlX21heCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbXVuaXR5ID0gY19jb3VudCwgY29tbXVuaXR5TWF4ID0gY19tYXgpKQogIH0KfQoKYGBgCgoKYGBge3J9CmJhcl93aWR0aCA9IDAuNQpkb2RnZV93aWR0aCA8LSAwICAjIEFkanVzdCB0aGlzIGFzIG5lZWRlZApleHBhbmRfbXVsdHMgPC0gYygwLCAwLjUpCnN1Ym1pc3Npb25Db3VudF9sZXZlbHMgPC0gYXMuY2hhcmFjdGVyKHVuaXF1ZShzdWJtaXNzaW9uX2RldGFpbGVkX2RmJHN1Ym1pc3Npb25Db3VudCkpCmZvciAodXNlciBpbiB1bmlxdWVVc2Vyc19maWx0ZXJlZCkgewogIGJfcGxvdCA8LSBnZ3Bsb3Qoc3VibWlzc2lvbl9kZXRhaWxlZF9kZiAlPiUgZmlsdGVyKHVzZXJLZXkgPT0gdXNlciksIGFlcyh4ID0gZmFjdG9yKHN1Ym1pc3Npb25Db3VudCkpKSArCiAgICBnZW9tX2JhcihhZXMoeSA9IGJ1c2luZXNzTWF4KSwgc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiZ2FpbnNib3JvIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IGRvZGdlX3dpZHRoKSwgd2lkdGggPSBiYXJfd2lkdGgpICsKICAgIGdlb21fYmFyKGFlcyh5ID0gYnVzaW5lc3MpLCBzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJjb3JuZmxvd2VyYmx1ZSIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSBkb2RnZV93aWR0aCksIHdpZHRoID0gYmFyX3dpZHRoKSArCiAgICBsYWJzKHRpdGxlID0gIkJ1c2luZXNzIiwKICAgICAgICAgeCA9ICJzdWJtaXNzaW9uQ291bnQiLAogICAgICAgICB5ID0gImNvdW50IiwKICAgICAgICAgZmlsbCA9ICJWYXJpYWJsZSIpICsKICAgIHRoZW1lX21pbmltYWwoKQogICMgKwogICMgICBzY2FsZV94X2Rpc2NyZXRlKGV4cGFuZCA9IGV4cGFuZF9zY2FsZShtdWx0ID0gZXhwYW5kX211bHRzLCBhZGQgPSBjKDAsIDApKSkKICAjIEFzc3VtaW5nIHRoZSByYW5nZSBvZiB5b3VyIHktYXhpcyBpcyBrbm93biBvciBjYW4gYmUgY2FsY3VsYXRlZDoKICB5X21heCA8LSBtYXgoc3VibWlzc2lvbl9kZXRhaWxlZF9kZiRidXNpbmVzc01heCwgbmEucm0gPSBUUlVFKQogICMgQ3JlYXRlIGEgc2VxdWVuY2UgZnJvbSAxIHRvIHRoZSBtYXhpbXVtIHZhbHVlIG9mIHksIGJ5IDEgdW5pdCBpbnRlcnZhbAogIGhsaW5lcyA8LSBzZXEoMSwgeV9tYXgsIGJ5ID0gMSkKICAjIEFkZCBob3Jpem9udGFsIGxpbmVzIHRvIHRoZSBwbG90CiAgYl9wbG90IDwtIGJfcGxvdCArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGhsaW5lcywgY29sb3IgPSAid2hpdGUiLCBsaW5ldHlwZSA9ICJzb2xpZCIpCiAgCiAgZV9wbG90IDwtIGdncGxvdChzdWJtaXNzaW9uX2RldGFpbGVkX2RmICU+JSBmaWx0ZXIodXNlcktleSA9PSB1c2VyKSwgYWVzKHggPSBmYWN0b3Ioc3VibWlzc2lvbkNvdW50KSkpICsKICAgIGdlb21fYmFyKGFlcyh5ID0gZW52aXJvbm1lbnRhbE1heCksIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gImdhaW5zYm9ybyIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSBkb2RnZV93aWR0aCksIHdpZHRoID0gYmFyX3dpZHRoKSArCiAgICBnZW9tX2JhcihhZXMoeSA9IGVudmlyb25tZW50YWwpLCBzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJmb3Jlc3RncmVlbiIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSBkb2RnZV93aWR0aCksIHdpZHRoID0gYmFyX3dpZHRoKSArCiAgICBsYWJzKHRpdGxlID0gIkVudmlyb25tZW50YWwiLAogICAgICAgICB4ID0gInN1Ym1pc3Npb25Db3VudCIsCiAgICAgICAgIHkgPSAiY291bnQiLAogICAgICAgICBmaWxsID0gIlZhcmlhYmxlIikgKwogICAgdGhlbWVfbWluaW1hbCgpCiAgeV9tYXggPC0gbWF4KHN1Ym1pc3Npb25fZGV0YWlsZWRfZGYkZW52aXJvbm1lbnRhbE1heCwgbmEucm0gPSBUUlVFKQogIGhsaW5lcyA8LSBzZXEoMSwgeV9tYXgsIGJ5ID0gMSkKICBlX3Bsb3QgPC0gZV9wbG90ICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gaGxpbmVzLCBjb2xvciA9ICJ3aGl0ZSIsIGxpbmV0eXBlID0gInNvbGlkIikKICAKICBjX3Bsb3QgPC0gZ2dwbG90KHN1Ym1pc3Npb25fZGV0YWlsZWRfZGYgJT4lIGZpbHRlcih1c2VyS2V5ID09IHVzZXIpLCBhZXMoeCA9IGZhY3RvcihzdWJtaXNzaW9uQ291bnQpKSkgKwogICAgZ2VvbV9iYXIoYWVzKHkgPSBjb21tdW5pdHlNYXgpLCBzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJnYWluc2Jvcm8iLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gZG9kZ2Vfd2lkdGgpLCB3aWR0aCA9IGJhcl93aWR0aCkgKwogICAgZ2VvbV9iYXIoYWVzKHkgPSBjb21tdW5pdHkpLCBzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJkYXJrb3JhbmdlIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IGRvZGdlX3dpZHRoKSwgd2lkdGggPSBiYXJfd2lkdGgpICsKICAgIGxhYnModGl0bGUgPSAiQ29tbXVuaXR5IiwKICAgICAgICAgeCA9ICJzdWJtaXNzaW9uQ291bnQiLAogICAgICAgICB5ID0gImNvdW50IiwKICAgICAgICAgZmlsbCA9ICJWYXJpYWJsZSIpICsKICAgIHRoZW1lX21pbmltYWwoKQogIHlfbWF4IDwtIG1heChzdWJtaXNzaW9uX2RldGFpbGVkX2RmJGNvbW11bml0eU1heCwgbmEucm0gPSBUUlVFKQogIGhsaW5lcyA8LSBzZXEoMSwgeV9tYXgsIGJ5ID0gMSkKICBjX3Bsb3QgPC0gY19wbG90ICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gaGxpbmVzLCBjb2xvciA9ICJ3aGl0ZSIsIGxpbmV0eXBlID0gInNvbGlkIikKICAKICBwcmludCgoYl9wbG90IC8gZV9wbG90IC8gY19wbG90KSArCiAgICBwbG90X2Fubm90YXRpb24odGl0bGUgPSB1c2VyKSkKfQpgYGAKCiMjIE9OQSBTZWN0aW9uCgoKCiMgMS4gY29tYmluZSBjb25zZXJ2YXRpb24gYW5kIGxpbWl0ZWQgdXNlIGFuZCBzZXQgc2VsZi1jb25uZWN0aW9uIHRvIHplcm8Kd2hpY2ggbWVhbnMgbHVjXzFfWCArIGx1Y180X1gsIGx1Y19YXzEgKyBsdWNfWF80CmBgYHtyfQpBX21hdHJpeF8yIDwtIEFfbWF0cml4CkJfbWF0cml4XzIgPC0gQl9tYXRyaXgKQ19tYXRyaXhfMiA8LSBDX21hdHJpeApmb3IgKGkgaW4gMToxMSkgewogIEFfbHVjMXggPSB3aGljaChuYW1lcyhBX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgMSwgIl8iLCBpLTEpKQogIEFfbHVjNHggPSB3aGljaChuYW1lcyhBX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgNCwgIl8iLCBpLTEpKQogIEJfbHVjMXggPSB3aGljaChuYW1lcyhCX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgMSwgIl8iLCBpLTEpKQogIEJfbHVjNHggPSB3aGljaChuYW1lcyhCX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgNCwgIl8iLCBpLTEpKQogIENfbHVjMXggPSB3aGljaChuYW1lcyhDX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgMSwgIl8iLCBpLTEpKQogIENfbHVjNHggPSB3aGljaChuYW1lcyhDX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgNCwgIl8iLCBpLTEpKQogIEFfbWF0cml4XzJbW0FfbHVjMXhdXSA8LSBBX21hdHJpeF8yW1tBX2x1YzF4XV0gKyBBX21hdHJpeF8yW1tBX2x1YzR4XV0KICBCX21hdHJpeF8yW1tCX2x1YzF4XV0gPC0gQl9tYXRyaXhfMltbQl9sdWMxeF1dICsgQl9tYXRyaXhfMltbQl9sdWM0eF1dCiAgQ19tYXRyaXhfMltbQ19sdWMxeF1dIDwtIENfbWF0cml4XzJbW0NfbHVjMXhdXSArIENfbWF0cml4XzJbW0NfbHVjNHhdXQp9CmZvciAoaSBpbiAxOjExKSB7CiAgQV9sdWN4MSA9IHdoaWNoKG5hbWVzKEFfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgMSkpCiAgQV9sdWN4NCA9IHdoaWNoKG5hbWVzKEFfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgNCkpCiAgQl9sdWN4MSA9IHdoaWNoKG5hbWVzKEJfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgMSkpCiAgQl9sdWN4NCA9IHdoaWNoKG5hbWVzKEJfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgNCkpCiAgQ19sdWN4MSA9IHdoaWNoKG5hbWVzKENfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgMSkpCiAgQ19sdWN4NCA9IHdoaWNoKG5hbWVzKENfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgNCkpCiAgQV9tYXRyaXhfMltbQV9sdWN4MV1dIDwtIEFfbWF0cml4XzJbW0FfbHVjeDFdXSArIEFfbWF0cml4XzJbW0FfbHVjeDRdXQogIEJfbWF0cml4XzJbW0JfbHVjeDFdXSA8LSBCX21hdHJpeF8yW1tCX2x1Y3gxXV0gKyBCX21hdHJpeF8yW1tCX2x1Y3g0XV0KICBDX21hdHJpeF8yW1tDX2x1Y3gxXV0gPC0gQ19tYXRyaXhfMltbQ19sdWN4MV1dICsgQ19tYXRyaXhfMltbQ19sdWN4NF1dCn0KZm9yIChpIGluIDE6MTEpIHsKICBBX2x1Y3h4ID0gd2hpY2gobmFtZXMoQV9tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIGktMSwgIl8iLCBpLTEpKQogIEJfbHVjeHggPSB3aGljaChuYW1lcyhCX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgaS0xLCAiXyIsIGktMSkpCiAgQ19sdWN4eCA9IHdoaWNoKG5hbWVzKENfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgaS0xKSkKICBBX21hdHJpeF8yW1tBX2x1Y3h4XV0gPSAwCiAgQl9tYXRyaXhfMltbQl9sdWN4eF1dID0gMAogIENfbWF0cml4XzJbW0NfbHVjeHhdXSA9IDAKfQoKQV9tYXRyaXhfMiA8LSBBX21hdHJpeF8yICU+JSBzZWxlY3QoLWMobHVjXzRfMCwgbHVjXzRfMSwgbHVjXzRfMiwgbHVjXzRfMywgbHVjXzRfNCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsdWNfNF81LCBsdWNfNF82LCBsdWNfNF83LCBsdWNfNF84LCBsdWNfNF85LCBsdWNfNF8xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx1Y18wXzQsIGx1Y18xXzQsIGx1Y18yXzQsIGx1Y18zXzQsIGx1Y180XzQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsdWNfNV80LCBsdWNfNl80LCBsdWNfN180LCBsdWNfOF80LCBsdWNfOV80LCBsdWNfMTBfNCkpCkJfbWF0cml4XzIgPC0gQl9tYXRyaXhfMiAlPiUgc2VsZWN0KC1jKGx1Y180XzAsIGx1Y180XzEsIGx1Y180XzIsIGx1Y180XzMsIGx1Y180XzQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHVjXzRfNSwgbHVjXzRfNiwgbHVjXzRfNywgbHVjXzRfOCwgbHVjXzRfOSwgbHVjXzRfMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsdWNfMF80LCBsdWNfMV80LCBsdWNfMl80LCBsdWNfM180LCBsdWNfNF80LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHVjXzVfNCwgbHVjXzZfNCwgbHVjXzdfNCwgbHVjXzhfNCwgbHVjXzlfNCwgbHVjXzEwXzQpKQpDX21hdHJpeF8yIDwtIENfbWF0cml4XzIgJT4lIHNlbGVjdCgtYyhsdWNfNF8wLCBsdWNfNF8xLCBsdWNfNF8yLCBsdWNfNF8zLCBsdWNfNF80LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx1Y180XzUsIGx1Y180XzYsIGx1Y180XzcsIGx1Y180XzgsIGx1Y180XzksIGx1Y180XzEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHVjXzBfNCwgbHVjXzFfNCwgbHVjXzJfNCwgbHVjXzNfNCwgbHVjXzRfNCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx1Y181XzQsIGx1Y182XzQsIGx1Y183XzQsIGx1Y184XzQsIGx1Y185XzQsIGx1Y18xMF80KSkKYGBgCgojIDIuIG1ha2UgQUJDIGNvbCBuYW1lcyBjb25zaXN0ZW50IGZvciB0aGUgZWFzZSBvZiBsYXRlciB3b3JrCmBgYHtyfQpjb2xuYW1lcyhBX21hdHJpeF8yKVsyXSA9ICJTSCIKQV9tYXRyaXhfMiA8LSBBX21hdHJpeF8yICU+JQogIHNlbGVjdCgtYyguLi4xKSkgJT4lIAogIGFkZF9jb2x1bW4odXNlcl9uYW1lID0gIk5BIiwgLmJlZm9yZSA9ICJsdWNfMF8wIikgJT4lCiAgYWRkX2NvbHVtbihzdWJtaXNzaW9uID0gIk5BIiwuYmVmb3JlID0gImx1Y18wXzAiKSAlPiUKICBhZGRfY29sdW1uKGluZGV4ID0gMTpucm93KEFfbWF0cml4KSwgLmJlZm9yZSA9ICJTSCIpCmBgYAoKYGBge3J9CmNvbG5hbWVzKEJfbWF0cml4XzIpWzJdID0gIlNIIgpCX21hdHJpeF8yIDwtIEJfbWF0cml4XzIgJT4lCiAgc2VsZWN0KC1jKC4uLjEpKSAlPiUgCiAgYWRkX2NvbHVtbih1c2VyX25hbWUgPSAiTkEiLCAuYmVmb3JlID0gImx1Y18wXzAiKSAlPiUKICBhZGRfY29sdW1uKHN1Ym1pc3Npb24gPSAiTkEiLC5iZWZvcmUgPSAibHVjXzBfMCIpICU+JQogIGFkZF9jb2x1bW4oaW5kZXggPSAxOm5yb3coQl9tYXRyaXgpLCAuYmVmb3JlID0gIlNIIikKYGBgCgpgYGB7cn0KQ19tYXRyaXhfMiA8LSBDX21hdHJpeF8yICU+JQogIGFkZF9jb2x1bW4oaW5kZXggPSAxOm5yb3coQ19tYXRyaXhfMiksIC5iZWZvcmUgPSAidXNlcl9uYW1lIikgJT4lCiAgYWRkX2NvbHVtbihOYW1lID0gIk5BIiwgLmJlZm9yZSA9ICJ1c2VyX25hbWUiKSAlPiUKICBhZGRfY29sdW1uKFNhdGlzZnkgPSAiTkEiLC5iZWZvcmUgPSAidXNlcl9uYW1lIikgJT4lCiAgYWRkX2NvbHVtbihOID0gIk5BIiwgLmJlZm9yZSA9ICJ1c2VyX25hbWUiKQpgYGAKCiMgMy5ydW4gT05BCmNhbGwgZ2VuZXJhdGUub25hLm9iamVjdCBmdW5jdGlvbgpgYGB7ciBnZW5lcmF0ZS5vbmEub2JqZWN0fQpnZW5lcmF0ZS5vbmEub2JqZWN0IDwtIGZ1bmN0aW9uKGRhdGEsIHVuaXQuY29sLCBtZXRhLmNvbCwgY29kZXMpewogIG91dHB1dCA8LSBsaXN0KCkKICBmLnVuaXRzIDwtIHVuaXQuY29sCiAgRU5BX1VOSVQgPC0gckVOQTo6bWVyZ2VfY29sdW1uc19jKGYudW5pdHMsIGNvbHMgPSBjb2xuYW1lcyhmLnVuaXRzKSk7CiAgIyBFTkFfVU5JVCA8LSAgZi51bml0cwogIGYucmF3IDwtIGRhdGEKICBmLmNvZGVzIDwtIGNvZGVzCiAgZGVuYV9kYXRhID0gZGlyZWN0ZWRFTkE6OjplbmEuc2V0LmRpcmVjdGVkKGYucmF3LCBmLnVuaXRzLCBOQSwgZi5jb2RlcykKICBvdXRwdXQubWV0YS5kYXRhIDwtIG1ldGEuY29sCiAgZGVuYV9kYXRhJG1ldGEuZGF0YSA8LSBkYXRhLnRhYmxlOjphcy5kYXRhLnRhYmxlKGNiaW5kKEVOQV9VTklULCBvdXRwdXQubWV0YS5kYXRhKSkKICBmb3IoIGkgaW4gY29sbmFtZXMoZGVuYV9kYXRhJG1ldGEuZGF0YSkgKSB7CiAgICBzZXQoZGVuYV9kYXRhJG1ldGEuZGF0YSwgaiA9IGksIHZhbHVlID0gckVOQTo6YXMuZW5hLm1ldGFkYXRhKGRlbmFfZGF0YSRtZXRhLmRhdGFbW2ldXSkpCiAgfQogIGNvZGVfbGVuZ3RoIDwtIGxlbmd0aChkZW5hX2RhdGEkcm90YXRpb24kY29kZXMpOwogIGRlbmFfZGF0YSRyb3RhdGlvbiRhZGphY2VuY3kua2V5IDwtIGRhdGEudGFibGU6OmRhdGEudGFibGUobWF0cml4KGMoCiAgICByZXAoMTpjb2RlX2xlbmd0aCwgY29kZV9sZW5ndGgpLAogICAgcmVwKDE6Y29kZV9sZW5ndGgsIGVhY2ggPSBjb2RlX2xlbmd0aCkpLAogICAgYnlyb3cgPSBUUlVFLCBucm93ID0gMgogICkpCiAgZGlyZWN0ZWQuYWRqYWNlbmN5LnZlY3RvcnMgPC0gYXMuZW5hLm1hdHJpeChkYXRhLnRhYmxlOjphcy5kYXRhLnRhYmxlKGRhdGFbLCBncmVwKCJWIiwgY29sbmFtZXMoZGF0YSkpXSksICJlbmEuY29ubmVjdGlvbnMiKQogICMgYXJlbid0IHRoZXNlIHR3byB0aGUgc2FtZSB0aGluZyAKICBkZW5hX2RhdGEkY29ubmVjdGlvbi5jb3VudHMgPC0gZGF0YS50YWJsZTo6YXMuZGF0YS50YWJsZShjYmluZChkZW5hX2RhdGEkbWV0YS5kYXRhLCBkaXJlY3RlZC5hZGphY2VuY3kudmVjdG9ycykpCiAgZGVuYV9kYXRhJGNvbm5lY3Rpb24uY291bnRzID0gckVOQTo6YXMuZW5hLm1hdHJpeCh4ID0gZGVuYV9kYXRhJGNvbm5lY3Rpb24uY291bnRzLCAiZW5hLmNvbm5lY3Rpb25zIikKICBmb3IgKGkgaW4gd2hpY2goIXJFTkE6OmZpbmRfbWV0YV9jb2xzKGRlbmFfZGF0YSRjb25uZWN0aW9uLmNvdW50cykpKQogICAgc2V0KGRlbmFfZGF0YSRjb25uZWN0aW9uLmNvdW50cywgaiA9IGksIHZhbHVlID0gYXMuZW5hLmNvLm9jY3VycmVuY2UoYXMuZG91YmxlKGRlbmFfZGF0YSRjb25uZWN0aW9uLmNvdW50c1tbaV1dKSkpCiAgZGVuYV9kYXRhJG1vZGVsJHJvdy5jb25uZWN0aW9uLmNvdW50cyA9IGRhdGEudGFibGU6OmFzLmRhdGEudGFibGUoY2JpbmQoZGVuYV9kYXRhJG1ldGEuZGF0YSwgZGlyZWN0ZWQuYWRqYWNlbmN5LnZlY3RvcnMpKQogIGRlbmFfZGF0YSRtb2RlbCRyb3cuY29ubmVjdGlvbi5jb3VudHMgPC0gckVOQTo6YXMuZW5hLm1hdHJpeChkZW5hX2RhdGEkbW9kZWwkcm93LmNvbm5lY3Rpb24uY291bnRzLCAicm93LmNvbm5lY3Rpb25zIikKICBvdXRwdXQgPSBkZW5hX2RhdGE7CiAgcmV0dXJuKG91dHB1dCkKfQpgYGAKCmBgYHtyfQojIDEuIHByZXBhcmUgZGYKCiMgZGYgPC0gQV9tYXRyaXgKIyBkZiA8LSBCX21hdHJpeApkZiA8LSBDX21hdHJpeF8yCgpuYW1lcyhkZilbNzoxMDZdIDwtIHBhc3RlMCgiViIsc2VxKDE6MTAwKSkKZGYkbWFwaWQgPSBtYXBpZAoKIyAyLiBhY2N1bQphY2N1bUMgPC0gZ2VuZXJhdGUub25hLm9iamVjdCgKICBkZiwKICB1bml0LmNvbCA9IGRmWywxOjddLAogIG1ldGEuY29sID0gZGZbLDE6N10sCiAgY29kZXMgPSBhcy52ZWN0b3IoCiAgICBjKCJDb21tZXJjaWFsIiwKICAgICJDb25zZXJ2YXRpb25fbHUiLAogICAgIyAiQ29uc2VydmF0aW9uIiwKICAgICJDcm9wbGFuZCIsCiAgICAiSW5kdXN0cmlhbCIsCiAgICAjICJMaW1pdGVkIFVzZSIsCiAgICAiUGFzdHVyZSIsCiAgICAiUmVjcmVhdGlvbiIsCiAgICAiUmVzaWRlbnRpYWwgSEQiLAogICAgIlJlc2lkZW50aWFsIExEIiwKICAgICJUaW1iZXIiLAogICAgIldldGxhbmRzIikpKQoKIyAzLiBtb2RlbApzZXRDIDwtIG1vZGVsKGFjY3VtQykKCiMgNC4gR29GCmNvcnJlbGF0aW9ucyhzZXRDKQoKYGBgCgpgYGB7cn0KIyAxLiBwcmVwYXJlIGRmCgpkZjEgPC0gQV9tYXRyaXhfMgojIGRmIDwtIEJfbWF0cml4CiMgZGYgPC0gQ19tYXRyaXgKCm5hbWVzKGRmMSlbNzoxMDZdIDwtIHBhc3RlMCgiViIsc2VxKDE6MTAwKSkKZGYxJG1hcGlkID0gbWFwaWQKCiMgMi4gYWNjdW0KYWNjdW1BIDwtIGdlbmVyYXRlLm9uYS5vYmplY3QoCiAgZGYxLAogIHVuaXQuY29sID0gZGYxWywxOjddLAogIG1ldGEuY29sID0gZGYxWywxOjddLAogIGNvZGVzID0gYXMudmVjdG9yKAogICAgYygiQ29tbWVyY2lhbCIsCiAgICAiQ29uc2VydmF0aW9uX2x1IiwKICAgICMgIkNvbnNlcnZhdGlvbiIsCiAgICAiQ3JvcGxhbmQiLAogICAgIkluZHVzdHJpYWwiLAogICAgIyAiTGltaXRlZCBVc2UiLAogICAgIlBhc3R1cmUiLAogICAgIlJlY3JlYXRpb24iLAogICAgIlJlc2lkZW50aWFsIEhEIiwKICAgICJSZXNpZGVudGlhbCBMRCIsCiAgICAiVGltYmVyIiwKICAgICJXZXRsYW5kcyIpKSkKCiMgMy4gbW9kZWwKc2V0QSA8LSBtb2RlbChhY2N1bUEpCgojIDQuIEdvRgpjb3JyZWxhdGlvbnMoc2V0QSkKYGBgCgojIDQuIHByb2plY3QgQyBwb2ludHMgaW50byBBIHNwYWNlClRvIGRvIHNvLCBJIG5lZWQgdG8gbWFrZSBhIHNldCB1c2luZyBDJ3MgYWNjdW11bGF0aW9uIGFuZCBBJ3Mgcm90YXRpb24gbWF0cml4CmBgYHtyfQpzZXQ9bW9kZWwoYWNjdW1DLCByb3RhdGlvbi5zZXQgPSBzZXRBJHJvdGF0aW9uKQpgYGAKCiMgNS4gb25hIHBsb3R0aW5nIAojIyA1LjEgc2V0dGluZyBnbG9iYWwgdmlzdWFsIHBhcmFtZXRlcnMgaGVyZSBzbyB0aGF0IGFsbCBPTkEgcGxvdHMgd2UgZ2VuZXJhdGUgYXJlIG9uIHRoZSBzYW1lIHNjYWxlCmBgYHtyfQpub2RlX3NpemVfbXVsdGlwbGllciA9IDAuMgpub2RlX3Bvc2l0aW9uX211bHRpcGxpZXIgPSAxLjAKZWRnZV9zaXplX211bHRpcGxpZXIgPSAwLjIKcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciA9IDEuMAplZGdlX2Fycm93X3NhdHVyYXRpb25fbXVsdGlwbGllciA9IDEuMApgYGAKCmBgYHtyfQpvbmE6OjpwbG90LmVuYS5vcmRlcmVkLnNldChzZXRDKSAlPiUgCiAgdW5pdHMoIAogICAgcG9pbnRzID0gc2V0QyRwb2ludHMsCiAgICBwb2ludHNfY29sb3IgPSAiYmxhY2siLAogICAgc2hvd19tZWFuID0gRkFMU0UsIHNob3dfcG9pbnRzID0gVFJVRSwgd2l0aF9jaSA9IEZBTFNFKQpgYGAKCiMjIDUuMiBxdWljayBjaGVjayBwb2ludHMgQVJFIGJlaW5nIHJvdGF0ZWQKYGBge3J9Cm9uYTo6OnBsb3QuZW5hLm9yZGVyZWQuc2V0KHNldEEsIHRpdGxlID0gInNwYWNlIHVzZWQgZm9yIHByb2plY3Rpb24gYW5kIGl0cyBwb2ludHMiKSAlPiUKICB1bml0cygKICAgIHBvaW50cyA9IHNldEEkcG9pbnRzLAogICAgcG9pbnRzX2NvbG9yID0gImdyYXkiLAogICAgc2hvd19tZWFuID0gVFJVRSwgc2hvd19wb2ludHMgPSBUUlVFLCB3aXRoX2NpID0gRkFMU0UpICU+JQogbm9kZXMoCiAgICBub2RlX3NpemVfbXVsdGlwbGllciA9IDAuMDAxKSAKCm9uYTo6OnBsb3QuZW5hLm9yZGVyZWQuc2V0KHNldEMsIHRpdGxlID0gInBvaW50cyBuZWVkIHRvIGJlIHByb2plY3RlZCBpbiBpdHMgb3JpZ2luYWwgc3BhY2UiKSAlPiUKICB1bml0cyggCiAgICBwb2ludHMgPSBzZXRDJHBvaW50cywKICAgIHBvaW50c19jb2xvciA9ICJibGFjayIsCiAgICBzaG93X21lYW4gPSBGQUxTRSwgc2hvd19wb2ludHMgPSBUUlVFLCB3aXRoX2NpID0gRkFMU0UpJT4lCiBub2RlcygKICAgIG5vZGVfc2l6ZV9tdWx0aXBsaWVyID0gMC4wMDEpIAoKb25hOjo6cGxvdC5lbmEub3JkZXJlZC5zZXQoc2V0LCB0aXRsZSA9ICJwcm9qZWN0ZWQgcG9pbnRzIGluIGl0cyBuZXcgc3BhY2UiKSAlPiUKICB1bml0cygKICAgIHBvaW50cyA9IHNldCRwb2ludHMsCiAgICBwb2ludHNfY29sb3IgPSAiYmxhY2siLAogICAgc2hvd19tZWFuID0gRkFMU0UsIHNob3dfcG9pbnRzID0gVFJVRSwgd2l0aF9jaSA9IEZBTFNFKSAlPiUKICB1bml0cygKICAgIHBvaW50cyA9IHNldEEkcG9pbnRzLAogICAgcG9pbnRzX2NvbG9yID0gImdyYXkiLAogICAgc2hvd19tZWFuID0gRkFMU0UsIHNob3dfcG9pbnRzID0gVFJVRSwgd2l0aF9jaSA9IEZBTFNFKSAlPiUKIG5vZGVzKAogICAgbm9kZV9zaXplX211bHRpcGxpZXIgPSAwLjAwMSkgCmBgYAoKIyMgQ2x1c3RlciBDaGVjazoKCgpgYGB7cn0Kb25hOjo6cGxvdC5lbmEub3JkZXJlZC5zZXQoc2V0QSwgdGl0bGUgPSAic3BhY2UgdXNlZCBmb3IgcHJvamVjdGlvbiBhbmQgaXRzIHBvaW50cyIpICU+JQogIHVuaXRzKAogICAgcG9pbnRzID0gc2V0QSRwb2ludHMsCiAgICBwb2ludHNfY29sb3IgPSAiZ3JheSIsCiAgICBzaG93X21lYW4gPSBUUlVFLCBzaG93X3BvaW50cyA9IFRSVUUsIHdpdGhfY2kgPSBGQUxTRSkgJT4lCiBub2RlcygKICAgIG5vZGVfc2l6ZV9tdWx0aXBsaWVyID0gMC4wMDEpIApgYGAKCmBgYHtyfQpBID0gc2V0QSRwb2ludHNbRU5BX0RJUkVDVElPTj09ICdyZXNwb25zZSddCmBgYAoKUGxvdCBib3RoIGJhciBwbG90cyBhbmQgb25hIHBsb3RzIGJ5IHNwZWNpZnlpbmcgdXNlcgoKYGBge3J9CnVuaXF1ZVVzZXJzX2ZpbHRlcmVkCmBgYAoKYGBge3J9CnVzZXJrZXkgPSAiQWlkYW5DMTI2IiAjIENoYW5nZSBhcyBhcHByb3ByaWF0ZQoKc3VicyA8LSBhcy5saXN0KHVuaXF1ZShzZXQkcG9pbnRzJEVOQV9VTklUKSkKc3VicyA8LSBzdWJzW2dyZXBsKHVzZXJrZXksIHN1YnMpXSAKb25hX3Bsb3RzIDwtIGxpc3QoKQoKZm9yIChpIGluIHN1YnMpIHsKICBwIDwtIG9uYTo6OnBsb3QuZW5hLm9yZGVyZWQuc2V0KHNldCwgdGl0bGUgPSBwYXN0ZTAoaSkpICU+JQogIGVkZ2VzKAogICAgICB3ZWlnaHRzID0gc2V0JGxpbmUud2VpZ2h0c1tFTkFfVU5JVCA9PSBpXSwKICAgICAgZWRnZV9zaXplX211bHRpcGxpZXIgPSBlZGdlX3NpemVfbXVsdGlwbGllciwKICAgICAgZWRnZV9hcnJvd19zYXR1cmF0aW9uX211bHRpcGxpZXIgPSBlZGdlX2Fycm93X3NhdHVyYXRpb25fbXVsdGlwbGllciwKICAgICAgbm9kZV9wb3NpdGlvbl9tdWx0aXBsaWVyID0gbm9kZV9wb3NpdGlvbl9tdWx0aXBsaWVyLAogICAgICBlZGdlX2NvbG9yID0gYygicmVkIikpICU+JQogIG5vZGVzKAogICAgbm9kZV9zaXplX211bHRpcGxpZXIgPSBub2RlX3NpemVfbXVsdGlwbGllciwKICAgIG5vZGVfcG9zaXRpb25fbXVsdGlwbGllciA9IG5vZGVfcG9zaXRpb25fbXVsdGlwbGllciwKICAgIHNlbGZfY29ubmVjdGlvbl9jb2xvciA9ICJyZWQiKSAgJT4lCiAgdW5pdHMoCiAgICAgIHBvaW50cz1zZXQkcG9pbnRzW0VOQV9VTklUID09IGldLAogICAgICBwb2ludHNfY29sb3IgPSAiYmxhY2siLAogICAgICBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyID0gcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciwKICAgICAgc2hvd19tZWFuID0gRkFMU0UsIHNob3dfcG9pbnRzID0gVFJVRSwgd2l0aF9jaSA9IEZBTFNFKSAlPiUKICB1bml0cygKICAgICAgcG9pbnRzID0gc2V0QSRwb2ludHNbU0ggPT0gc2hfbmFtZVsxXSAmIFNhdGlzZnkgPT0gIlllcyJdLAogICAgICBwb2ludHNfY29sb3IgPSAiZ3JlZW4iLAogICAgICBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyID0gcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciwKICAgICAgc2hvd19tZWFuID0gVFJVRSwgc2hvd19wb2ludHMgPSBGQUxTRSwgd2l0aF9jaSA9IEZBTFNFKSAlPiUKICB1bml0cygKICAgICAgcG9pbnRzID0gc2V0QSRwb2ludHNbU0ggPT0gc2hfbmFtZVsyXSAmIFNhdGlzZnkgPT0gIlllcyJdLAogICAgICBwb2ludHNfY29sb3IgPSAiYmx1ZSIsCiAgICAgIHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIgPSBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyLAogICAgICBzaG93X21lYW4gPSBUUlVFLCBzaG93X3BvaW50cyA9IEZBTFNFLCB3aXRoX2NpID0gRkFMU0UpICU+JQogIHVuaXRzKAogICAgICBwb2ludHMgPSBzZXRBJHBvaW50c1tTSCA9PSBzaF9uYW1lWzNdICYgU2F0aXNmeSA9PSAiWWVzIl0sCiAgICAgIHBvaW50c19jb2xvciA9ICJicm93biIsCiAgICAgIHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIgPSBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyLAogICAgICBzaG93X21lYW4gPSBUUlVFLCBzaG93X3BvaW50cyA9IEZBTFNFLCB3aXRoX2NpID0gRkFMU0UpICU+JQogIHVuaXRzKAogICAgICBwb2ludHMgPSBzZXRBJHBvaW50c1tTSCA9PSBzaF9uYW1lWzRdICYgU2F0aXNmeSA9PSAiWWVzIl0sCiAgICAgIHBvaW50c19jb2xvciA9ICJwdXJwbGUiLAogICAgICBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyID0gcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciwKICAgICAgc2hvd19tZWFuID0gVFJVRSwgc2hvd19wb2ludHMgPSBGQUxTRSwgd2l0aF9jaSA9IEZBTFNFKSAlPiUKICB1bml0cygKICAgICAgcG9pbnRzID0gc2V0QSRwb2ludHNbU0ggPT0gc2hfbmFtZVs1XSAmIFNhdGlzZnkgPT0gIlllcyJdLAogICAgICBwb2ludHNfY29sb3IgPSAieWVsbG93IiwKICAgICAgcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciA9IHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIsCiAgICAgIHNob3dfbWVhbiA9IFRSVUUsIHNob3dfcG9pbnRzID0gRkFMU0UsIHdpdGhfY2kgPSBGQUxTRSkgJT4lCiAgdW5pdHMoCiAgICAgIHBvaW50cyA9IHNldEEkcG9pbnRzW1NIID09IHNoX25hbWVbNl0gJiBTYXRpc2Z5ID09ICJZZXMiXSwKICAgICAgcG9pbnRzX2NvbG9yID0gImRlZXBwaW5rIiwKICAgICAgcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciA9IHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIsCiAgICAgIHNob3dfbWVhbiA9IFRSVUUsIHNob3dfcG9pbnRzID0gRkFMU0UsIHdpdGhfY2kgPSBGQUxTRSkgJT4lCiAgdW5pdHMoCiAgICAgIHBvaW50cyA9IHNldEEkcG9pbnRzW1NIID09IHNoX25hbWVbN10gJiBTYXRpc2Z5ID09ICJZZXMiXSwKICAgICAgcG9pbnRzX2NvbG9yID0gIlRhbiIsCiAgICAgIHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIgPSBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyLAogICAgICBzaG93X21lYW4gPSBUUlVFLCBzaG93X3BvaW50cyA9IEZBTFNFLCB3aXRoX2NpID0gRkFMU0UpICU+JQogIHVuaXRzKAogICAgICBwb2ludHMgPSBzZXRBJHBvaW50c1tTSCA9PSBzaF9uYW1lWzhdICYgU2F0aXNmeSA9PSAiWWVzIl0sCiAgICAgIHBvaW50c19jb2xvciA9ICJDeWFuIiwKICAgICAgcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciA9IHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIsCiAgICAgIHNob3dfbWVhbiA9IFRSVUUsIHNob3dfcG9pbnRzID0gRkFMU0UsIHdpdGhfY2kgPSBGQUxTRSkgJT4lCiAgdW5pdHMoCiAgICAgIHBvaW50cyA9IHNldEEkcG9pbnRzW1NIID09IHNoX25hbWVbOV0gJiBTYXRpc2Z5ID09ICJZZXMiXSwKICAgICAgcG9pbnRzX2NvbG9yID0gIm9yYW5nZSIsCiAgICAgIHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIgPSBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyLAogICAgICBzaG93X21lYW4gPSBUUlVFLCBzaG93X3BvaW50cyA9IEZBTFNFLCB3aXRoX2NpID0gRkFMU0UpJT4lIAogICAgICBwbG90bHk6OmxheW91dChzaG93bGVnZW5kID0gVFJVRSwgbGVnZW5kID0gbGlzdCh4ID0gMTAwLCB5ID0gMC45KSkgJT4lIAogICAgICBzdHlsZShuYW1lID0gInBvaW50IiwgdHJhY2VzID0gYygyKSkgJT4lIAogICAgc3R5bGUobmFtZSA9IHNoX2luZm9bMV0sIHRyYWNlcyA9IGMoMykpICU+JSAKICAgIHN0eWxlKG5hbWUgPSBzaF9pbmZvWzJdLCB0cmFjZXMgPSBjKDQpKSAlPiUgCiAgICBzdHlsZShuYW1lID0gc2hfaW5mb1szXSwgdHJhY2VzID0gYyg1KSkgJT4lIAogICAgc3R5bGUobmFtZSA9IHNoX2luZm9bNF0sIHRyYWNlcyA9IGMoNikpICU+JSAKICAgIHN0eWxlKG5hbWUgPSBzaF9pbmZvWzVdLCB0cmFjZXMgPSBjKDcpKSAlPiUgCiAgICBzdHlsZShuYW1lID0gc2hfaW5mb1s2XSwgdHJhY2VzID0gYyg4KSkgJT4lIAogICAgc3R5bGUobmFtZSA9IHNoX2luZm9bN10sIHRyYWNlcyA9IGMoOSkpICU+JSAKICAgIHN0eWxlKG5hbWUgPSBzaF9pbmZvWzhdLCB0cmFjZXMgPSBjKDEwKSkgJT4lIAogICAgc3R5bGUobmFtZSA9IHNoX2luZm9bOV0sIHRyYWNlcyA9IGMoMTEpKQogIG9uYV9wbG90c1tbaV1dIDwtIHAKfQoKYGBgCgpgYGB7cn0KYmFyX3dpZHRoID0gMC41CmRvZGdlX3dpZHRoIDwtIDAgICMgQWRqdXN0IHRoaXMgYXMgbmVlZGVkCmV4cGFuZF9tdWx0cyA8LSBjKDAsIDAuNSkKc3VibWlzc2lvbkNvdW50X2xldmVscyA8LSBhcy5jaGFyYWN0ZXIodW5pcXVlKHN1Ym1pc3Npb25fZGV0YWlsZWRfZGYkc3VibWlzc2lvbkNvdW50KSkKCmJfcGxvdCA8LSBnZ3Bsb3Qoc3VibWlzc2lvbl9kZXRhaWxlZF9kZiAlPiUgZmlsdGVyKHVzZXJLZXkgPT0gdXNlcmtleSksIGFlcyh4ID0gZmFjdG9yKHN1Ym1pc3Npb25Db3VudCkpKSArCiAgZ2VvbV9iYXIoYWVzKHkgPSBidXNpbmVzc01heCksIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gImdhaW5zYm9ybyIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSBkb2RnZV93aWR0aCksIHdpZHRoID0gYmFyX3dpZHRoKSArCiAgZ2VvbV9iYXIoYWVzKHkgPSBidXNpbmVzcyksIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gImNvcm5mbG93ZXJibHVlIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IGRvZGdlX3dpZHRoKSwgd2lkdGggPSBiYXJfd2lkdGgpICsKICBsYWJzKHRpdGxlID0gIkJ1c2luZXNzIiwKICAgICAgIHggPSAic3VibWlzc2lvbkNvdW50IiwKICAgICAgIHkgPSAiY291bnQiLAogICAgICAgZmlsbCA9ICJWYXJpYWJsZSIpICsKICB0aGVtZV9taW5pbWFsKCkKIyArCiMgICBzY2FsZV94X2Rpc2NyZXRlKGV4cGFuZCA9IGV4cGFuZF9zY2FsZShtdWx0ID0gZXhwYW5kX211bHRzLCBhZGQgPSBjKDAsIDApKSkKIyBBc3N1bWluZyB0aGUgcmFuZ2Ugb2YgeW91ciB5LWF4aXMgaXMga25vd24gb3IgY2FuIGJlIGNhbGN1bGF0ZWQ6CnlfbWF4IDwtIG1heChzdWJtaXNzaW9uX2RldGFpbGVkX2RmJGJ1c2luZXNzTWF4LCBuYS5ybSA9IFRSVUUpCiMgQ3JlYXRlIGEgc2VxdWVuY2UgZnJvbSAxIHRvIHRoZSBtYXhpbXVtIHZhbHVlIG9mIHksIGJ5IDEgdW5pdCBpbnRlcnZhbApobGluZXMgPC0gc2VxKDEsIHlfbWF4LCBieSA9IDEpCiMgQWRkIGhvcml6b250YWwgbGluZXMgdG8gdGhlIHBsb3QKYl9wbG90IDwtIGJfcGxvdCArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGhsaW5lcywgY29sb3IgPSAid2hpdGUiLCBsaW5ldHlwZSA9ICJzb2xpZCIpCgplX3Bsb3QgPC0gZ2dwbG90KHN1Ym1pc3Npb25fZGV0YWlsZWRfZGYgJT4lIGZpbHRlcih1c2VyS2V5ID09IHVzZXJrZXkpLCBhZXMoeCA9IGZhY3RvcihzdWJtaXNzaW9uQ291bnQpKSkgKwogIGdlb21fYmFyKGFlcyh5ID0gZW52aXJvbm1lbnRhbE1heCksIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gImdhaW5zYm9ybyIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSBkb2RnZV93aWR0aCksIHdpZHRoID0gYmFyX3dpZHRoKSArCiAgZ2VvbV9iYXIoYWVzKHkgPSBlbnZpcm9ubWVudGFsKSwgc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiZm9yZXN0Z3JlZW4iLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gZG9kZ2Vfd2lkdGgpLCB3aWR0aCA9IGJhcl93aWR0aCkgKwogIGxhYnModGl0bGUgPSAiRW52aXJvbm1lbnRhbCIsCiAgICAgICB4ID0gInN1Ym1pc3Npb25Db3VudCIsCiAgICAgICB5ID0gImNvdW50IiwKICAgICAgIGZpbGwgPSAiVmFyaWFibGUiKSArCiAgdGhlbWVfbWluaW1hbCgpCnlfbWF4IDwtIG1heChzdWJtaXNzaW9uX2RldGFpbGVkX2RmJGVudmlyb25tZW50YWxNYXgsIG5hLnJtID0gVFJVRSkKaGxpbmVzIDwtIHNlcSgxLCB5X21heCwgYnkgPSAxKQplX3Bsb3QgPC0gZV9wbG90ICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gaGxpbmVzLCBjb2xvciA9ICJ3aGl0ZSIsIGxpbmV0eXBlID0gInNvbGlkIikKCmNfcGxvdCA8LSBnZ3Bsb3Qoc3VibWlzc2lvbl9kZXRhaWxlZF9kZiAlPiUgZmlsdGVyKHVzZXJLZXkgPT0gdXNlcmtleSksIGFlcyh4ID0gZmFjdG9yKHN1Ym1pc3Npb25Db3VudCkpKSArCiAgZ2VvbV9iYXIoYWVzKHkgPSBjb21tdW5pdHlNYXgpLCBzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJnYWluc2Jvcm8iLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gZG9kZ2Vfd2lkdGgpLCB3aWR0aCA9IGJhcl93aWR0aCkgKwogIGdlb21fYmFyKGFlcyh5ID0gY29tbXVuaXR5KSwgc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiZGFya29yYW5nZSIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSBkb2RnZV93aWR0aCksIHdpZHRoID0gYmFyX3dpZHRoKSArCiAgbGFicyh0aXRsZSA9ICJDb21tdW5pdHkiLAogICAgICAgeCA9ICJzdWJtaXNzaW9uQ291bnQiLAogICAgICAgeSA9ICJjb3VudCIsCiAgICAgICBmaWxsID0gIlZhcmlhYmxlIikgKwogIHRoZW1lX21pbmltYWwoKQp5X21heCA8LSBtYXgoc3VibWlzc2lvbl9kZXRhaWxlZF9kZiRjb21tdW5pdHlNYXgsIG5hLnJtID0gVFJVRSkKaGxpbmVzIDwtIHNlcSgxLCB5X21heCwgYnkgPSAxKQpjX3Bsb3QgPC0gY19wbG90ICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gaGxpbmVzLCBjb2xvciA9ICJ3aGl0ZSIsIGxpbmV0eXBlID0gInNvbGlkIikKCnByaW50KChiX3Bsb3QgLyBlX3Bsb3QgLyBjX3Bsb3QpICsKICBwbG90X2Fubm90YXRpb24odGl0bGUgPSB1c2Vya2V5KSkKCmZvciAocCBpbiBvbmFfcGxvdHMpIHsKICBwcmludChwKQp9CmBgYAoKCgo=